package com.hnx.admin.aurora.system.service.impl;

import com.hnx.admin.aurora.annotation.LoginValidator;
import com.hnx.admin.aurora.annotation.Pager;
import com.hnx.admin.aurora.annotation.RepeatValidator;
import com.hnx.admin.aurora.api.cache.CacheAPI;
import com.hnx.admin.aurora.api.http.HttpStatusAPI;
import com.hnx.admin.aurora.api.menu.MenuCacheAPI;
import com.hnx.admin.aurora.enums.BusinessType;
import com.hnx.admin.aurora.jwt.api.JwtAPI;
import com.hnx.admin.aurora.jwt.config.JwtUtil;
import com.hnx.admin.aurora.redis.RedisCache;
import com.hnx.admin.aurora.security.context.AuthenticationContextHolder;
import com.hnx.admin.aurora.security.utils.SecurityUtil;
import com.hnx.admin.aurora.system.domain.convert.user.UserConvert;
import com.hnx.admin.aurora.system.domain.dto.post.entity.SysPostDTO;
import com.hnx.admin.aurora.system.domain.dto.role.entity.RoleDTO;
import com.hnx.admin.aurora.system.domain.dto.user.entity.UserDTO;
import com.hnx.admin.aurora.system.domain.param.dept.query.DeptQuery;
import com.hnx.admin.aurora.system.domain.param.role.query.UserRoleQuery;
import com.hnx.admin.aurora.system.domain.param.user.form.*;
import com.hnx.admin.aurora.system.domain.param.user.query.LoginQuery;
import com.hnx.admin.aurora.system.domain.param.user.query.UserQuery;
import com.hnx.admin.aurora.system.domain.vo.menu.entity.MenuVO;
import com.hnx.admin.aurora.system.domain.vo.meta.entity.MetaVO;
import com.hnx.admin.aurora.system.domain.vo.post.entity.SysPostVO;
import com.hnx.admin.aurora.system.domain.vo.role.entity.RoleVO;
import com.hnx.admin.aurora.system.domain.vo.router.entity.RouterVO;
import com.hnx.admin.aurora.system.domain.vo.user.entity.UserDetailVO;
import com.hnx.admin.aurora.system.domain.vo.user.entity.UserVO;
import com.hnx.admin.aurora.system.mapper.emp.EmpMapper;
import com.hnx.admin.aurora.system.mapper.user.UserMapper;
import com.hnx.admin.aurora.system.mapper.userPost.UserPostMapper;
import com.hnx.admin.aurora.system.mapper.userRole.UserRoleMapper;
import com.hnx.admin.aurora.system.service.*;
import com.hnx.admin.aurora.utils.ExcelUtil;
import com.hnx.admin.aurora.utils.ServletUtil;
import com.hnx.admin.aurora.utils.TreeUtil;
import com.hnx.admin.aurora.web.exception.user.UserInfoException;
import com.hnx.admin.aurora.web.exception.user.UsernameEmptyException;
import com.hnx.admin.aurora.web.json.ResultJson;
import com.hnx.admin.aurora.web.json.TreeNodeVO;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/*
创建人： 倔强的头发
创建时间：2025/6/14
功能描述:

*/
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService, JwtAPI, MenuCacheAPI, HttpStatusAPI, CacheAPI {
    private final UserMapper userMapper;
    private final UserPostMapper userPostMapper;
    private final UserRoleMapper userRoleMapper;
    private final EmpMapper empMapper;
    private final UserConvert userConvert;
    private final RoleService roleService;
    private final MenuService menuService;
    private final SysPostService sysPostService;
    private final JwtUtil jwtUtil;
    private final RedisCache redisCache;
    private final DeptService deptService;

    @Lazy
    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserDTO user = userMapper.selectUserByUsername(username).orElseThrow(UsernameEmptyException::new);
        UserVO userVO = userConvert.toVO(user);
        Set<String> list = menuService.getPermissionByUser(userVO);
        return new UserDetailVO(userVO, user.getPassword(), list);
    }

    @Override
    @LoginValidator
    public ResultJson login(LoginQuery loginBody) {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginBody.getUsername(), loginBody.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        AuthenticationContextHolder.setContext(authenticate);
        UserDetailVO principal = (UserDetailVO) authenticate.getPrincipal();
        Map<String, String> map = new HashMap<>();
        map.put(LOGIN_USER_KEY, loginBody.getUuid());
        map.put(USER_ID, principal.getUserVO().getUserId());
        String token = jwtUtil.createToken(map);
        jwtUtil.setRedisCache(loginBody.getUuid(), principal);
        return ResultJson.success().add("token", token);

    }

    private UserDetailVO getUserInfo() {
        HttpServletRequest request = ServletUtil.getRequest();
        String userKey = jwtUtil.getUserKey(request);
        return redisCache.getCacheObject(userKey, UserDetailVO.class);
    }

    @Override
    public ResultJson getInfo() {
        UserDetailVO userDetailVO = getUserInfo();
        List<RoleVO> list = roleService.getRoleByUserId(userDetailVO.getUserVO().getUserId());
        return ResultJson.success().add("permissions", userDetailVO.getPermission()).add("roles", list).add("user", userDetailVO.getUserVO());
    }

    @Override
    public ResultJson getInfo(String userId) {
        List<SysPostVO> postList = sysPostService.getPostList();
        List<RoleVO> roleList = roleService.getRoleList();
        ResultJson json = ResultJson.success().add("roles", !(userId != null && (userId.equals("16458486670656798720"))) ? roleList : roleList.stream().filter(r -> !r.getRoleKey().equals("admin")).collect(Collectors.toList())).add("posts", postList);
        if (org.springframework.util.StringUtils.hasText(userId)) {
            UserDTO user = userMapper.selectUserById(userId).orElseThrow(UserInfoException::new);
            UserVO userVO = userConvert.toVO(user);
            json.add("data", userVO);
            json.add("roleIds", user.getRoleList().stream().map(RoleDTO::getRoleId));
            json.add("postIds", user.getPostList().stream().map(SysPostDTO::getPostId));
        }
        return json;
    }

    @Override
    public ResultJson getRouters() {
        UserDetailVO userInfo = getUserInfo();
        List<MenuVO> list = menuService.selectMenuTreeByUser(userInfo.getUserVO());
        return ResultJson.data(TreeUtil.buildTreeAndMap(list, MenuVO::getMenuId, "0", Comparator.comparing(MenuVO::getOrderNum), this::ConvertToRouterVO));
    }

    @Override
    @Pager(orderBy = " b.create_time ")
    public ResultJson getUserList(UserQuery userParam) {
        List<UserDTO> list = userMapper.getUserList(userParam);
        List<UserVO> lst = userConvert.toList(list);
        return ResultJson.rows(lst);
    }

    @Override
    public ResultJson deptTree(DeptQuery dept) {
        List<TreeNodeVO> list = deptService.selectDeptList(dept);
        return ResultJson.data(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @RepeatValidator(type = BusinessType.UPDATE)
    public ResultJson updateUser(UserForm user) {
        int res = userMapper.updateUser(user);
        empMapper.updateEmp(user);
        userPostMapper.removeUserPost(user.getUserId());
        if(user.getPostIds() != null && user.getPostIds().length >0) {
            userPostMapper.insertUserPost(user.getUserId(),user.getPostIds());
        }
        userRoleMapper.removeUserRole(user.getUserId());
        if(user.getRoleIds() != null && user.getRoleIds().length > 0) {
            UserRoleForm userRoleForm = new UserRoleForm();
            userRoleForm.setRoleIds(user.getRoleIds());
            userRoleForm.setUserId(user.getUserId());
            userRoleMapper.insertUserRole(user.getUserId(),userRoleForm.getRoleIds());
        }
        return ResultJson.condition(res);
    }

    @Override
    public ResultJson updateUserStatus(UserForm user) {
        if(StringUtils.isBlank(user.getUserId())){
            ResultJson.fail("用户标识信息不能为空");
        }
        int res = userMapper.updateUserStatus(user);
        return ResultJson.condition(res);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultJson deleteUserByIds(UserDelForm user) {
        UserDetailVO userDetailVO = (UserDetailVO) SecurityUtil.getPrincipal();
        if (Arrays.stream(user.getUserIds()).anyMatch(n -> n == userDetailVO.getUserVO().getUserId())) {
            return ResultJson.fail("不能删除当前用户");
        }
        int res = userMapper.deleteUserByIds(user);
        userRoleMapper.removeUserRoles(user.getUserIds());
        userPostMapper.removeUserPosts(user.getUserIds());
        return ResultJson.condition(res);
    }

    @Override
    public ResultJson resetPwd(UserForm user) {
        if(StringUtils.isBlank(user.getPassword())){
            return ResultJson.fail("密码不能为空");
        }
        String password = SecurityUtil.encryptPassword(user.getPassword());
        user.setPassword(password);
        int res = userMapper.updateUserPassword(user);
        return ResultJson.condition(res);
    }

    @Override
    public ResultJson selectRolesByUserId(String userId) {
        UserDTO user = userMapper.selectUserById(userId).orElseThrow(UsernameEmptyException::new);
        List<RoleVO> list = roleService.getRoleList();
        Set<String> roleIds = user.getRoleList().stream().map((RoleDTO::getRoleId)).collect(Collectors.toSet());
        list.stream().filter(n->roleIds.contains(n.getRoleId())).forEach(r->r.setFlag(true));
        return ResultJson.success().add("user", user).add("roles",list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultJson insertUserAuth(UserRoleForm user) {
        userRoleMapper.removeUserRole(user.getUserId());
        if(user.getRoleIds() != null && user.getRoleIds().length>0) {
            userRoleMapper.insertUserRole(user.getUserId(), user.getRoleIds());
        }
        return ResultJson.success();
    }

    @Override
    @RepeatValidator(type = BusinessType.INSERT)
    @Transactional(rollbackFor = Exception.class)
    public ResultJson insertUser(UserForm user) {
        user.setPassword(SecurityUtil.encryptPassword(user.getPassword()));
        int rows = userMapper.insertUser(user);
        empMapper.insertEmp(user);
        if(user.getPostIds() != null && user.getRoleIds().length > 0){
            userPostMapper.insertUserPost(user.getUserId(), user.getPostIds());
        }
        if(user.getRoleIds() != null && user.getRoleIds().length > 0){
            userRoleMapper.insertUserRole(user.getUserId(),user.getRoleIds());
        }
        return ResultJson.success();
    }

    @Override
    public void export(HttpServletResponse response) throws IOException, NoSuchFieldException {
        List<UserDTO> list = userMapper.getUserList(null);
        ExcelUtil.exportExcel(response, list,"测试",  UserDTO.class);
    }

    @Override
    @Pager
    public ResultJson selectAllocatedList(UserRoleQuery user) {
        List<UserDTO> list = userMapper.selectAllocatedList(user);
        if(list != null && list.size() > 0) {
            return ResultJson.rows(userConvert.toList(list));
        }
        return ResultJson.rows(list);
    }

    @Override
    @Pager
    public ResultJson selectUnallocatedList(UserRoleQuery user) {
        List<UserDTO> list = userMapper.selectUnallocatedList(user);
        if(list != null && list.size() > 0) {
            return ResultJson.rows(userConvert.toList(list));
        }
        return ResultJson.rows(list);
    }

    /**
     * 将菜单映射为路由信息
     *
     * @param menuVO 菜单对象
     * @return 结果
     */
    private RouterVO ConvertToRouterVO(MenuVO menuVO) {
        RouterVO routerVO = new RouterVO();
        routerVO.setHidden("1".equals(menuVO.getVisible()));
        routerVO.setName(StringUtils.capitalize(org.springframework.util.StringUtils.hasText(menuVO.getRouteName()) ? menuVO.getRouteName() : menuVO.getPath()));
        routerVO.setPath(menuVO.getMenuType().equals(TYPE_DIR) && menuVO.getParentId().equals("0") ? "/" + menuVO.getPath() : menuVO.getPath());
        routerVO.setComponent(getComponent(menuVO));
        routerVO.setQuery(menuVO.getQuery());
        routerVO.setMeta(new MetaVO(menuVO.getMenuName(), menuVO.getIcon(), StringUtils.equals("1", menuVO.getIsCache()), menuVO.getPath()));
        if (Objects.nonNull(menuVO.getChildren()) && menuVO.getChildren().size() > 0) {
            routerVO.setAlwaysShow(true);
            routerVO.setRedirect("noRedirect");
            List<RouterVO> list = menuVO.getChildren().stream().collect(Collectors.mapping(this::ConvertToRouterVO, Collectors.toList()));
            routerVO.setChildren(list);
        }
        return routerVO;
    }

    /**
     * 获取组件信息
     *
     * @param menu 菜单信息
     * @return 组件信息
     */
    public String getComponent(MenuVO menu) {
        String component = LAYOUT;
        if (StringUtils.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu)) {
            component = menu.getComponent();
        } else if (StringUtils.isEmpty(menu.getComponent()) && !menu.getParentId().equals("0") && isInnerLink(menu)) {
            component = INNER_LINK;
        } else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu)) {
            component = PARENT_VIEW;
        }
        return component;
    }

    /**
     * 是否为parent_view组件
     *
     * @param menu 菜单信息
     * @return 结果
     */
    public boolean isParentView(MenuVO menu) {
        return !menu.getParentId().equals("0") && TYPE_DIR.equals(menu.getMenuType());
    }

    /**
     * 是否为内链组件
     *
     * @param menu 菜单信息
     * @return 结果
     */
    public boolean isInnerLink(MenuVO menu) {
        return menu.getIsFrame().equals(NO_FRAME) && StringUtils.startsWithAny(menu.getPath(), HTTP, HTTPS);
    }

    /**
     * 是否为菜单内部跳转
     *
     * @param menu 菜单信息
     * @return 结果
     */
    public boolean isMenuFrame(MenuVO menu) {
        return menu.getParentId().equals("0") && TYPE_MENU.equals(menu.getMenuType())
                && menu.getIsFrame().equals(NO_FRAME);
    }
}
